using NUnit.Framework;
using Tycho.Parser.Peg;

namespace Tycho.Parser.Tests.Peg {
    [TestFixture]
    public class DelimitedRuleSpecification {
        [Test]
        public void ShouldParseDelimitedTokens () {
            var element = new DelimitedRule (new LiteralRule (IdentifierProduction.CreateTerminal ()), new KeywordRule (","));

            var source = "a, b, c, d, e";

            var result = element.Parse (source, 0, new ParseContext ());
            Assert.IsNotNull (result);
            Assert.AreEqual (13, result.Index);
        }

        [Test]
        public void ShouldParseUpToHangingDelimiter () {
            var element = new DelimitedRule (new LiteralRule (IdentifierProduction.CreateTerminal ()), new KeywordRule (","));

            var source = "a, b, c, d,";

            var result = element.Parse (source, 0, new ParseContext ());
            Assert.IsNotNull (result);
            Assert.AreEqual (11, result.Index);
        }

        [Test]
        public void ShouldParseNothing () {
            var element = new DelimitedRule (new LiteralRule (IdentifierProduction.CreateTerminal ()), new KeywordRule (","));

            var source = "";

            var result = element.Parse (source, 0, new ParseContext ());
            Assert.IsNotNull (result);
            Assert.AreEqual (0, result.Index);
        }

        [Test]
        public void ShouldParseNothingIfFirstProductionDoesntParse () {
            var element = new DelimitedRule (new NamedRule ("a", IdentifierProduction.CreateTerminal ()), new KeywordRule (","));

            var source = "8";

            var result = element.Parse (source, 0, new ParseContext ());
            Assert.IsNotNull (result);
            Assert.AreEqual (0, result.Index);
        }

        [Test]
        public void ShouldPassThroughContextFromItemToDelimiter () {
            var id = IdentifierProduction.CreateTerminal ();
            id.ResultTransform = r => {
                                     r.Context = r.Context.Clone ();
                                     r.Context.BracketDepth++;
                                     return r;
                                 };
            var keyword = PunctuationProduction.CreateTerminal (",");
            keyword.ResultTransform = r => {
                                          r.Context = r.Context.Clone ();
                                          r.Context.BracketDepth++;
                                          return r;
                                      };
            var element = new DelimitedRule (new LiteralRule (id), new LiteralRule (keyword));

            var source = "a, b, c, d";

            var result = element.Parse (source, 0, new ParseContext ());
            Assert.AreEqual (7, result.Context.BracketDepth);
        }

        [Test]
        public void ShouldReturnAllCaptures () {
            var rule = new DelimitedRule (new NamedRule ("item", IdentifierProduction.CreateTerminal ()), new NamedRule ("delimiter", IdentifierProduction.CreateTerminal ()));

            var source = "a b c";

            var result = rule.Parse (source, 0, new ParseContext ());
            Assert.AreEqual (3, result.Captures.Count);
            result.AssertCaptureIs (0, "item", "a");
            result.AssertCaptureIs (1, "delimiter", "b");
            result.AssertCaptureIs (2, "item", "c");
        }
    }
}